import sys
socket = None
if sys.platform.startswith('NOATIN'):
    print("micropython")
    socket =  __import__('usocket')
    global unicode
    unicode = str
else:
    socket =  __import__('socket')
    print("python")
# Echo server program
class NoatinMessage:
    msgtype = ''
    value = ''
    name = ''


class NoatinConnection:
    _started = False
    msgHandlers0 = {}
    msgHandlers1 = {}
    msgHandlers2 = {}
    conn = None
    addr = False
    comein = ''
    #comein_search_start = 0
    start_flag = 'nUoDiNg'
    start_flag_length = 7
    def __init__(self, port):
        self.port = port
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)

    def _accept(self):
        if self._socket is None:
            #print 'could not open socket'
            return
        try:
            conn, addr = self._socket.accept()
            self.conn = conn
            self.addr = addr
            self.conn.settimeout(0.01)
            return True
        except socket.error as msg:
            pass
        except socket.timeout as msg:
            pass
        return False

    def start(self):
        if self._socket is None:
            #print 'could not open socket'
            return
        self._socket.bind(('', self.port))
        self._socket.settimeout(0.01)
        self._socket.listen(1)
        self._started = True
        self._accept()
        return

    def send(self, msg):
        if not self.conn:
            return
        self.conn.sendall(msg)

    def _call_handlers(self,hdlist,arg):
        for hd in hdlist:
            hd(arg)

    def _handle_message(self, msg):
        msgtype = msg.msgtype
        msg_handlers = None
        if msgtype == '0':
            msg_handlers = self.msgHandlers0
        elif msgtype == '1':
            msg_handlers = self.msgHandlers1
            anykeyHandler = self.msgHandlers1.get("ANY")
            if anykeyHandler:
                #anyHandler(msg)
                self._call_handlers(anykeyHandler,msg)
        elif msgtype == '2':
            msg_handlers = self.msgHandlers2
        elif msgtype == '3':
            self._socket.close()
            self._socket = None
        msg_handler = msg_handlers.get(msg.name)
        if msg_handler:
            #msg_handler(msg)
            self._call_handlers(msg_handler,msg)

    def register_message_handler(self, msgtype, msg_name, handler):
        msg_handlers = None
        if msgtype == '0':
            msg_handlers = self.msgHandlers0
        elif msgtype == '1':
            msg_handlers = self.msgHandlers1
        elif msgtype == '2':
            msg_handlers = self.msgHandlers2
        hdlist = msg_handlers.get(msg_name)
        if not hdlist:
            hdlist = []
            msg_handlers[msg_name] = hdlist
        hdlist.append(handler)

    def _parse_message(self, msgstring):
        msg = NoatinMessage()
        msgtype = msgstring[0]
        msg.msgtype = msgtype
        firstcolon = msgstring.find(':')
        str_firstlength = msgstring[1:firstcolon]
        firstlength = int(str_firstlength)
        first = msgstring[firstcolon + 1 : firstcolon + 1 + firstlength]
        if msgtype == '0':
            value = msgstring[firstcolon + 1 + firstlength:]
            msg.name = first
            msg.value = value
        elif msgtype == '1':
            msg.name = first
        elif msgtype == '2':
            msg.name = first
        return msg

    def receive_message(self):
        if not self.conn:
            if not self._accept():
                return False
        try:
            data = self.conn.recv(1024)
            if not data:
                self.conn.shutdown(socket.SHUT_RDWR)
                self.conn.close()
                self.conn = None
            self.comein = self.comein + data
            start = self.comein.find(self.start_flag)
            if start < 0:
                return False
            else:
                if start != 0:
                    self.comein = self.comein[start:]
                firstcolon = self.comein.find(':')
                if firstcolon < 0:
                    return False
                else:
                    length = self.comein[self.start_flag_length : firstcolon]
                    #print 'length',length
                    #print 'self.start_flag_length',self.start_flag_length
                    #print 'firstcolon',firstcolon
                    #print 'self.comein',self.comein
                    wanted_comein_length = self.start_flag_length + 1 + int(length) + 1
                    if len(self.comein) >= wanted_comein_length:
                        msgstring = self.comein[firstcolon + 1: wanted_comein_length + 1]
                        #print 'message',msgstring
                        self.comein = self.comein[wanted_comein_length:]
                        msg = self._parse_message(msgstring)
                        self._handle_message(msg)
                        return True
                    else:
                        return False

        except socket.timeout as msg:
            return False
        except socket.error as msg:
            #print msg
            self.conn.close()
            self.conn = None
            self.comein = ''
        return False

    def loop_recive_messages(self):
        while(self.receive_message()):
            pass

    def noatin_message_send(self,msgtype,title,content,target_actor_id):
        msgtype = str(msgtype)
        title = unicode(title)
        content = unicode(content)
        target_actor_id = unicode(target_actor_id)
        len_title = str(len(title))
        len_content = str(len(content))
        len_target_actor_id = str(len(target_actor_id))
        msg = ":" + msgtype + len_title + ":" + title + len_content + ":" + content + len_target_actor_id + ":" + target_actor_id
        msg = self.start_flag + str(len(msg)) + msg
        #print "send",msg
        if self.conn:
            try:
                self.conn.sendall(msg)
                #print "OK."
            except socket.error:
                #print "Exception:", sys.exc_info()
                self.conn.close()
                self.conn = None
                self.comein = ''
        else:
            #print "Not connected."
            pass
        